Skip to content

fix(wsl): 修复 WSL 仓库 Git 操作失效与侧边栏路径显示异常#340

Merged
J3n5en merged 3 commits intoJ3n5en:mainfrom
moulai:fix/wsl-bugs
Mar 5, 2026
Merged

fix(wsl): 修复 WSL 仓库 Git 操作失效与侧边栏路径显示异常#340
J3n5en merged 3 commits intoJ3n5en:mainfrom
moulai:fix/wsl-bugs

Conversation

@moulai
Copy link
Contributor

@moulai moulai commented Mar 4, 2026

背景

在 Windows + WSL 仓库场景下,存在以下问题:

  1. 版本管理可显示 Diff,但暂存/提交无效,审查或 commit 提示内容为空
  2. 侧边栏路径显示异常(UNC 路径在视觉上出现末尾 \\ 错位)
  3. 仓库名/分支相关展示在部分路径场景下解析不稳定
  4. 新建 Agent 后 Tab 名称会被 wsl.exe 终端标题覆盖

变更说明

1) WSL Git 路径与命令执行修复(仅 WSL 生效)

  • GitServicestage/unstage/commit(files) 时,仅对 WSL 仓库做路径标准化
  • commit-message 在 WSL 下改为通过 spawnGit 获取 staged 信息,避免 UNC cwd 导致内容为空
  • 非 WSL 路径保持原逻辑,不改变原有行为

2) 侧边栏路径显示修复(最小非侵入)

  • 根因是路径行使用 direction: rtl 时,UNC 前缀 \\ 在视觉上会跑到末尾
  • 新增 isWslUncPath 判断,仅在 WSL UNC 路径显示时切换为 direction: ltr
  • 其他路径继续保持原 rtl 行为(保留原有“优先显示路径尾部”体验)
  • 同类位置统一修复:
    • RepositorySidebar
    • TreeSidebar
    • WorktreePanel
    • TemporaryWorkspacePanel

3) 路径工具统一(DRY)

  • 抽取并复用:
    • getPathBasename
    • trimTrailingPathSeparators
    • isWslUncPath
  • 替换分散的 split(/[\\/]) 逻辑,统一路径名解析行为

4) Agent Tab 名称稳定性

  • SessionBar 终端标题过滤规则新增 wsl(.exe),避免 Agent 名称被终端标题覆盖

影响范围与兼容性

  • 仅新增 WSL 条件分支与显示层修复
  • 不修改数据结构、IPC 协议、存储格式
  • 非 WSL 路径行为保持不变

验证

  • 已通过本地提交前格式化/检查(lint-staged)
  • pnpm typecheck 仍有既有历史错误(SessionBar.tsx(399)onDoubleClick 类型),与本 PR 无关

- GitService 仅在 WSL 仓库标准化 stage/unstage/commit(files) 路径,修复可见 diff 但无法暂存/提交\n- commit-message 在 WSL 下改用 spawnGit 获取 staged 信息,修复审查/提交提示内容为空\n- 修复侧边栏 UNC 路径在 RTL 下视觉错位问题;仅 WSL UNC 路径切换为 LTR,其他路径保持原行为\n- 抽取并复用路径工具 getPathBasename/trimTrailingPathSeparators/isWslUncPath,替换分散 split 逻辑\n- SessionBar 增加 wsl.exe 终端标题过滤,避免 Agent 名称被终端标题覆盖\n\n- 影响范围最小化:仅 WSL 条件分支与显示层修复,不改现有数据结构与非 WSL 功能路径
@github-actions

This comment has been minimized.

- runGit(WSL) 分支增加 stderr drain,避免 stderr 管道缓冲区填满导致子进程阻塞\n- 去除 spawnGit(cwd, args, { cwd }) 中冗余的 cwd 传参,简化调用
@github-actions

This comment has been minimized.

- commit-message: 为 WSL runGit 增加 settled 防止 timeout/close 竞态下重复 resolve\n- shared/path + git/runtime: 统一复用 WSL_UNC_PREFIXES,避免前后端判定规则漂移\n- WorktreePanel/TreeSidebar: 拖拽预览路径统一使用 getPathBasename,替换分散 split 逻辑
@github-actions
Copy link
Contributor

github-actions bot commented Mar 4, 2026

Claude finished @moulai's task in 2m 58s —— View job


🔍 代码审查报告

👋 审查已完成! 以下是对本次 WSL 修复 PR 的详细分析和建议。
💡 使用提示:点击 📁 文件链接可直接跳转到代码位置,建议按优先级处理问题。


📊 审查概览 · 一目了然

📋 审查项目 🔢 发现数量 📈 占比 🎯 处理状态
📁 审查文件 14 100% 已完成
🚨 严重问题 0 0%
⚠️ 中等问题 2 40% 🟡 本版本修复
轻微问题 3 60% 🔵 后续优化

🏆 代码质量评分

📊 综合评分: 85/100  🌟🌟🌟🌟⭐
📋 本次等级: 良好

📋 问题分布

🚨 严重: ░░░░░░░░░░  0%
⚠️ 中等: ████░░░░░░ 40%
⚡ 轻微: ██████░░░░ 60%
总体评分: ⭐⭐⭐⭐☆ (4/5)

🎯 关键发现

🏷️ 类别 🔍 发现数量 🎯 优先级 📈 趋势
🔒 安全性 0 个 ✅ 无 ✅ 良好
⚡ 性能 1 个 🟡 中 📊 平稳
🎨 代码质量 3 个 🔵 低 📉 改善
🛠️ 健壮性 1 个 🟡 中 📊 平稳

✅ 亮点

  • 路径工具统一 (path.ts)getPathBasenametrimTrailingPathSeparatorsisWslUncPath 抽取得当,DRY 原则执行到位,WSL_UNC_PREFIXES 作为单一真相来源(SSOT)在 renderer/main 间复用非常合理
  • 最小侵入原则:WSL 条件分支仅在必要路径加入,非 WSL 场景完全不受影响
  • commit-message.tsrunGit 封装:stderr drain 避免管道堵塞,settled flag 防竞态,实现稳健
  • UI 修复策略direction: ltr/rtl 的条件切换方案简洁有效,避免了复杂的 CSS hack

🎯 问题详细分析 · 📊 点击展开查看

📊 **👆 点击此处展开详细统计和图表分析**

📈 问题趋势分析

本次审查: 🟡🟡🔵🔵🔵 (发现 5 个问题)
代码质量: ████████░░ 85%
安全评分: ██████████ 100% ✅
性能评分: ████████░░ 80%  ✅
🏆 质量指标 📊 当前分数 🎯 目标分数 📈 改进方向
代码质量 85/100 90+ ⬆️ 少量改进
安全等级 100/100 100 ✅ 优秀
性能优化 80/100 85+ ⬆️ 轻微优化

🐛 问题清单与修复指南 · 📋 点击展开查看

📋 **👆 点击此处展开详细问题列表 (共 5 个问题) · 一键复制追踪 📌**

🚀 快速开始

⚠️ 中等级别 (Major) 建议修复

🟡 #1 src/main/services/ai/commit-message.ts:56-63

🏷️ 类型: 健壮性 | ⏰ 优先级: P1 - 本版本修复 | 🎯 影响范围: WSL commit 消息生成

  • 🔍 问题描述runGit 中 WSL 分支的超时处理:当 proc.kill('SIGKILL') 被调用时,如果进程已在 close 事件处理中但 settled 尚未被检查,存在微小的竞态窗口。此外,proc.on('error') 中的 clearTimeoutproc.on('close') 都会执行,但 error 事件触发后通常还会触发 close,第二次进入 close 时因 settled=true 被跳过是安全的。

    不过更关键的是:SIGKILL 是不可捕获信号,子进程会立即终止,不会有 graceful shutdown。对于 wsl.exe 包裹的 git 进程,SIGKILL 可能无法正确终止 WSL 内部的 git 进程,导致僵尸进程。

    // src/main/services/ai/commit-message.ts:56-63
    const timeout = setTimeout(() => {
      if (settled) return;
      settled = true;
      if (!proc.killed) {
        proc.kill('SIGKILL');
      }
      resolve('');
    }, 5000);
  • 🛠️ 解决方案:建议先尝试 SIGTERM,给进程一个 graceful shutdown 的机会,如果仍未退出再考虑 SIGKILL

    const timeout = setTimeout(() => {
      if (settled) return;
      settled = true;
      if (!proc.killed) {
        proc.kill('SIGTERM');
      }
      resolve('');
    }, 5000);
  • ⚠️ 潜在影响:WSL 场景下可能残留 git 进程


🟡 #2 src/main/services/ai/commit-message.ts:39-86

🏷️ 类型: 性能/可维护性 | ⏰ 优先级: P1 - 本版本修复 | 🎯 影响范围: commit 消息生成

  • 🔍 问题描述runGit 函数在非 WSL 分支中使用同步的 execSync,这会阻塞 Node.js 主进程(main process)的事件循环。虽然 timeout 设为 5000ms,但在此期间主进程完全无法响应其他 IPC 请求。这个问题在 WSL 分支中已正确使用异步 spawnGit,但非 WSL 分支被保留为同步调用。

    // src/main/services/ai/commit-message.ts:41-48
    if (!isWslGitRepository(cwd)) {
      try {
        return Promise.resolve(
          execSync(`git ${args.join(' ')}`, { cwd, encoding: 'utf-8', timeout: 5000 }).trim()
        );
      } catch {
        return Promise.resolve('');
      }
    }
  • 🛠️ 解决方案:考虑将非 WSL 分支也改为异步调用(使用 execAsync 或统一使用 spawnGit),以避免主进程阻塞。不过这属于既有代码的问题,如果本 PR 不想扩大变更范围,可以在后续版本处理。

  • ⚠️ 潜在影响:commit 消息生成期间主进程阻塞约 1-5 秒


⚡ 轻微级别 (Minor) 优化建议

🔵 #3 src/shared/utils/path.ts:51-54

🏷️ 类型: 性能微优化 | ⏰ 优先级: P2 - 后续版本 | 🎯 影响范围: 全局路径判断

  • 🔍 问题描述isWslUncPath 每次调用都执行 replace(/\\/g, '/')toLowerCase(),在 UI 渲染中被频繁调用(如列表渲染)时会产生不必要的字符串分配。

    // src/shared/utils/path.ts:51-54
    export function isWslUncPath(inputPath: string): boolean {
      const normalized = inputPath.replace(/\\/g, '/');
      return WSL_UNC_PREFIXES.some((prefix) => normalized.toLowerCase().startsWith(prefix));
    }
  • 🛠️ 解决方案:可以先做快速前缀检查来提前返回,避免不必要的字符串操作:

    export function isWslUncPath(inputPath: string): boolean {
      if (!inputPath.startsWith('\\\\') && !inputPath.startsWith('//')) return false;
      const normalized = inputPath.replace(/\\/g, '/');
      return WSL_UNC_PREFIXES.some((prefix) => normalized.toLowerCase().startsWith(prefix));
    }
  • ⚠️ 潜在影响:纯优化,当前性能已足够


🔵 #4 src/renderer/components/chat/SessionBar.tsx:225

🏷️ 类型: 正则表达式可读性 | ⏰ 优先级: P2 - 后续版本 | 🎯 影响范围: Agent Tab 名称

  • 🔍 问题描述wsl 已被添加到终端标题过滤正则中,逻辑正确。但当前正则表达式已经包含较多 shell 名称(pwsh|powershell|cmd|bash|zsh|sh|fish|nu|wsl),随着过滤条件增多,建议考虑将过滤列表抽为常量数组以提高可维护性。

    // src/renderer/components/chat/SessionBar.tsx:225
    if (/[/\\](pwsh|powershell|cmd|bash|zsh|sh|fish|nu|wsl)(\.exe)?["']?\s*$/i.test(title)) {
  • 🛠️ 解决方案:这只是一个可读性建议,当前实现功能完全正确:

    const SHELL_NAMES = ['pwsh', 'powershell', 'cmd', 'bash', 'zsh', 'sh', 'fish', 'nu', 'wsl'];
    const SHELL_REGEX = new RegExp(`[/\\\\](${SHELL_NAMES.join('|')})(\\.exe)?["']?\\s*$`, 'i');
  • ⚠️ 潜在影响:纯可读性优化,无功能影响


🔵 #5 src/renderer/components/layout/RepositorySidebar.tsx:313-314 及同类位置

🏷️ 类型: 一致性 | ⏰ 优先级: P2 - 后续版本 | 🎯 影响范围: UI 展示

  • 🔍 问题描述:四个组件(RepositorySidebar、TreeSidebar、WorktreePanel、TemporaryWorkspacePanel)中的 WSL 路径方向判断逻辑完全一致:isWslUncPath(path) ? '[direction:ltr]' : '[direction:rtl]'。虽然当前各处的用法很简单(一行 ternary),但如果未来需要调整策略(如支持更多特殊路径格式),修改点会分散。

    // src/renderer/components/layout/RepositorySidebar.tsx:314
    const useLtrPathDisplay = isWslUncPath(repo.path);
  • 🛠️ 解决方案:可考虑在 path.ts 中导出一个 getPathDirection(path: string): 'ltr' | 'rtl' helper,或者保持现状——因为当前复杂度完全可控。这只是一个前瞻性建议。

  • ⚠️ 潜在影响:纯可维护性建议


📊 修复优先级矩阵

🎯 优先级 🚨 严重 ⚠️ 中等 ⚡ 轻微 📈 总计
🔴 P0 0 个 - - 0 个
🟡 P1 - 2 个 - 2 个
🔵 P2 - - 3 个 3 个
📊 合计 0 2 3 5 个

🎯 合并决策建议

📋 合并评估结果

📊 评估维度 ⭐ 得分 🎯 状态 💭 说明
🔐 安全性 10/10 ✅ 通过 无安全隐患,路径处理规范
📊 代码质量 8/10 ✅ 良好 工具函数设计合理,DRY 原则遵循好
⚡ 性能影响 8/10 ✅ 无明显影响 execSync 阻塞为既有问题,非本 PR 引入
🛠️ 功能完整性 9/10 ✅ 完整 四个问题全部修复,覆盖范围充分
🧪 测试覆盖 6/10 ⚠️ 基本 缺少 path.ts 工具函数的单元测试

📈 综合评分: 41/50 分 · 等级: 良好


🚦 最终建议

建议合并

📝 详细理由

  • 🟢 本 PR 修复了 WSL 场景下 4 个明确的 bug,变更逻辑清晰、影响范围可控
  • 🟢 采用最小侵入原则,非 WSL 路径行为完全不受影响
  • 🟢 路径工具函数提取合理,减少了分散的 split(/[\\/]/) 逻辑
  • 🟢 无安全问题,无数据结构/IPC 协议变更
  • 🟡 SIGKILL vs SIGTERMexecSync 阻塞是值得注意的改进点,但不阻塞合并

🎯 具体行动建议

  1. 可选改进(不阻塞合并)

    • #1 考虑将 SIGKILL 改为 SIGTERM 以避免 WSL 僵尸进程
    • #3isWslUncPath 添加快速前缀检查
  2. 后续版本改进

    • src/shared/utils/path.ts 新增函数添加单元测试
    • #2commit-message.ts 非 WSL 分支的 execSync 迁移为异步调用

  • 收集 PR 变更上下文
  • 审查共享工具代码 (path.ts)
  • 审查主进程变更 (Git/commit-message)
  • 审查渲染进程变更 (UI 组件)
  • 生成审查报告

@J3n5en J3n5en merged commit fd09e15 into J3n5en:main Mar 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants